package microkernel

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"sync"
)

const (
	Waiting = iota // 等待中
	Running        // 运行中
)

var ErrWrongStateError = errors.New("can not take the operation in the current state")

type CollectorsError struct {
	CollectorErrors []error
}

func (ce CollectorsError) Error() string {
	var strs []string
	for _, err := range ce.CollectorErrors {
		strs = append(strs, err.Error())
	}
	return strings.Join(strs, ";")
}

type Event struct {
	Source  string
	Content string
}

type Agent struct {
	collectors map[string]Collector // 收集器map，方便查询
	evtBuf     chan Event           // 事件处理结果队列
	cancel     context.CancelFunc   // 取消函数
	ctx        context.Context      // 上下文
	state      int                  // 收集器状态
}

func (agt *Agent) EventProcessGoroutine() {
	var evtSeg [10]Event
	// 10个结果一组打印 收集器的事件结果
	for {
		for i := 0; i < 10; i++ {
			select {
			case evtSeg[i] = <-agt.evtBuf:
			case <-agt.ctx.Done():
				return
			}
		}
		fmt.Println(evtSeg)
	}

}

// 创建Agent
func NewAgent(sizeEvtBuf int) *Agent {
	agt := Agent{
		collectors: map[string]Collector{},
		evtBuf:     make(chan Event, sizeEvtBuf),
		state:      Waiting,
	}
	return &agt
}

// 注册收集器
func (agt *Agent) RegisterCollector(name string, collector Collector) error {
	// 非等待状态 不允许注册收集器
	if agt.state != Waiting {
		return ErrWrongStateError
	}
	// 注册收集器
	agt.collectors[name] = collector
	// 初始化收集器
	return collector.Init(agt)
}

func (agt *Agent) startCollectors() error {
	var err error
	var errs CollectorsError
	var mutex sync.Mutex

	// 异步开启所有的收集器，若发送错误则收集错误，一个收集器出错并不影响其他收集器
	for name, collector := range agt.collectors {
		go func(name string, collector Collector, ctx context.Context) {
			defer func() {
				mutex.Unlock()
			}()
			err = collector.Start(ctx)
			mutex.Lock()
			if err != nil {
				errs.CollectorErrors = append(errs.CollectorErrors, errors.New(name+":"+err.Error()))
			}
		}(name, collector, agt.ctx)
	}
	if len(errs.CollectorErrors) == 0 {
		return nil
	}
	return errs
}

func (agt *Agent) stopCollectors() error {
	var err error
	var errs CollectorsError
	// 停止所有的收集器，若发送错误则收集错误，一个收集器出错并不影响其他收集器
	for name, collector := range agt.collectors {
		if err = collector.Stop(); err != nil {
			errs.CollectorErrors = append(errs.CollectorErrors,
				errors.New(name+":"+err.Error()))
		}
	}
	if len(errs.CollectorErrors) == 0 {
		return nil
	}
	return errs
}

func (agt *Agent) destoryCollectors() error {
	var err error
	var errs CollectorsError
	// 销毁所有的收集器，若发送错误则收集错误，一个收集器出错并不影响其他收集器
	for name, collector := range agt.collectors {
		if err = collector.Destroy(); err != nil {
			errs.CollectorErrors = append(errs.CollectorErrors,
				errors.New(name+":"+err.Error()))
		}
	}
	if len(errs.CollectorErrors) == 0 {
		return nil
	}
	return errs
}

// 开启Agent服务
func (agt *Agent) Start() error {
	// 非等待状态 不开启Agent服务
	if agt.state != Waiting {
		return ErrWrongStateError
	}
	// 更新状态为运行中
	agt.state = Running
	// 设置 context和取消函数
	agt.ctx, agt.cancel = context.WithCancel(context.Background())
	// 异步开启事件处理
	go agt.EventProcessGoroutine()
	// 开启收集器
	return agt.startCollectors()
}

func (agt *Agent) Stop() error {
	// 非运行状态 不可停止
	if agt.state != Running {
		return ErrWrongStateError
	}
	agt.state = Waiting
	// 执行取消函数,停止所有的收集器任务
	agt.cancel()
	// 这里执行的，收集器的停止方法，和上面的取消不一样
	// agt.cancel()          停止收集器运行中的任务
	// agt.stopCollectors()  停止方法停止整个收集器
	return agt.stopCollectors()
}

func (agt *Agent) Destory() error {
	// 非运行状态 不可销毁
	if agt.state != Waiting {
		return ErrWrongStateError
	}
	return agt.destoryCollectors()
}

func (agt *Agent) OnEvent(evt Event) {
	// 事件结果放入事件处理结果队列
	agt.evtBuf <- evt
}
